package com.gsafety.devops.util;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PortScanner {
	
	
	
	public static String scanPort(String ip, int port, int timeout) {
		Socket socket = new Socket();
		SocketAddress socketAddress = new InetSocketAddress(ip, port);
		try {
			socket.connect(socketAddress, timeout);
			socket.close();
			System.out.println("端口 " + port + " ：开放");
			return "Open";
		} catch (IOException e) {
			// 产生异常表示端口关闭
			System.out.println("端口 " + port + " ：关闭");
		}
		return "Closed";
	}
	

	/**
	 * 多线程扫描目标主机指定List端口集合的开放情况
	 *
	 * @param ip
	 *            待扫描IP或域名
	 * @param portList
	 *            待扫描的端口的List集合
	 * @param threadNumber
	 *            线程数
	 * @param timeout
	 *            连接超时时间
	 */
	public void scanPorts(String ip, List<Integer> portSet, int threadNumber, int timeout) {
		ExecutorService threadPool = Executors.newCachedThreadPool();
		// 线程池
		for (int i = 0; i < threadNumber; i++) {
			// 10个线程 加入到线程池里
			ScanMethod scanMethod2 = new ScanMethod(ip, portSet, threadNumber, i, timeout);
			threadPool.execute(scanMethod2);
		}
		threadPool.shutdown();
		while (true) {
			if (threadPool.isTerminated()) {
				System.out.println("扫描结束");
				break;
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} // end of while
	}

	/*
	 * 扫描方式：针对一个待扫描的端口的List集合进行扫描
	 */
	private class ScanMethod implements Runnable {
		private String ip; // 目标IP
		private List<Integer> portList; // 待扫描的端口的List集合
		private int threadNumber, serial, timeout; // 线程数，这是第几个线程，超时时间

		public ScanMethod(String ip, List<Integer> portList, int threadNumber, int serial, int timeout) {
			this.ip = ip;
			this.portList = portList;
			this.threadNumber = threadNumber;
			this.serial = serial;
			this.timeout = timeout;
		}

		public void run() {
			int port = 0;
			Integer[] ports = portList.toArray(new Integer[portList.size()]); // List转数组
			try {
				InetAddress address = InetAddress.getByName(ip); // 如果输入的是主机名，尝试获取ip地址
				Socket socket;// 定义套接字
				SocketAddress socketAddress;// 传递ip和端口
				if (ports.length < 1)
					// 若数组没有元素，返回，不执行
					return;
				for (port = 0 + serial; port <= ports.length - 1; port += threadNumber) {
					// 每次运行10个线程
					socket = new Socket();
					// 为对象分配内存空间
					socketAddress = new InetSocketAddress(address, ports[port]);
					try {
						socket.connect(socketAddress, timeout);
						// 对目标主机的指定端口进行连接，超时后连接失败
						socket.close();
						// 关闭端口
						System.out.println("端口 " + ports[port] + " ：开放");
						// 在文本区域里更新消息
					} catch (IOException e) {
						System.out.println("端口 " + ports[port] + " ：关闭");
						// 产生异常表示端口关闭
					}
				}
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
		}
		// end of run()
	}// end of ScanMethod

	public static void main(String[] args) {
		PortScanner p = new PortScanner();
		Integer[] ports = new Integer[] { 21, 22, 23, 25, 26, 53, 69, 80, 110, 143, 443, 465, 69, 161, 162, 135, 995, 1080,
				1158, 1433, 1521, 2100, 3128, 3306, 3389, 7001, 8080, 8081, 9080, 9090, 43958, 135, 445, 1025, 1026, 1027,
				1028, 1055, 5357 };
		List<Integer> portList = new LinkedList<Integer>();// 定义一个List容器表示扫描的团口的List集合
		portList.addAll(Arrays.asList(ports));
		p.scanPorts("127.0.0.1", portList, 50, 500);
	}
	
	
}
